#include "usb_fp_protocol.h"
#include "common.h"
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

static uint32_t g_prot_chip_addr = 0xffffffff;      //消息头部

static uint16_t ofp_checksum_16bit(uint8_t *buf, uint32_t len)
{
    uint32_t i = 0;
    uint16_t checksum = 0;

    if (buf == NULL) {
        return 0;
    }
    for (i = 0; i < len; i++) {
        checksum += buf[i];
    }
    return (checksum);
}
static void ofp_recv_param_init(ofp_recv_data_param *param, uint32_t recv_len, uint16_t wait_ms, uint16_t cycle_times, uint16_t cycle_ms)
{
    memset(param, 0x00, sizeof(ofp_recv_data_param));

    param->recv_len = recv_len;
    param->wait_ms = wait_ms;
    param->cycle_times = cycle_times;
    param->cycle_ms = cycle_ms;
}

static uint32_t ofp_fill_usb_cmd_packet(msg_struct *msg,
    uint8_t cmd, uint8_t subcmd,  uint8_t *send_data, uint16_t send_data_len)
{
    uint32_t i = 0;
    uint16_t checksum = 0;
    uint16_t data_len = 0;
    uint32_t pkg_len = 0;

    msg->head.pkg_head = htons(0xEF01);
    msg->head.chip_addr = htonl(g_prot_chip_addr);
    msg->head.pkg_flag = PROT_TYPE_CMD;

    if (cmd != PROT_CMD_NULL) {
        msg->data[i++] = cmd;
    }
    if (subcmd != PROT_SUBCMD_NULL) {
        msg->data[i++] = subcmd;
    }
    if ((send_data == NULL) && (send_data_len == 0)) {
        //do nothing
    }else {
        memcpy(msg->data + i, send_data, send_data_len);
    }

    data_len = (uint16_t)(i  + send_data_len + CHIP_CHECKSUM_SIZE);

    msg->head.data_len = htons(data_len);

    checksum = ofp_checksum_16bit(&(msg->head.pkg_flag), data_len - CHIP_CHECKSUM_SIZE +
        sizeof(msg->head.pkg_flag) + sizeof(msg->head.data_len));
    msg->data[data_len - 2] = ((uint8_t)((checksum >> 8u) & 0xff));

    msg->data[data_len - 1] = ((uint8_t)(checksum & 0xff));
    pkg_len = sizeof(msg->head) + data_len;

    return pkg_len;

}

static int32_t ofp_check_usb_cmd_resp_packet(msg_struct *msg, cmd_struct *cmd)
{
    uint16_t checksum = 0;
    uint32_t checksum_index = 0;
    if ((msg->head.chip_addr != htonl(g_prot_chip_addr)) || (msg->head.pkg_head != htons(0xEF01)) ||
        (msg->head.pkg_flag != PROT_TYPE_RESPOND)) {
        OFP_LOGE("ofp_parse_usb_cmd_packet head parse error \n");
        return PROT_ERROR_PARSE;
    }


    checksum = ofp_checksum_16bit(&(msg->head.pkg_flag), ntohs(msg->head.data_len) - CHIP_CHECKSUM_SIZE +
        sizeof(msg->head.pkg_flag) + sizeof(msg->head.data_len));

    checksum_index = ntohs(msg->head.data_len) - CHIP_CHECKSUM_SIZE;

    if ((((checksum >> 8) & 0xff) != msg->data[checksum_index]) ||
        ((checksum  & 0xff) != msg->data[checksum_index + 1])) {

        OFP_LOGE("ofp_parse_usb_cmd_packet crc error \n");
        return PROT_ERROR_PARSE;
    }
    cmd->recv_data_len = ntohs(msg->head.data_len) - CHIP_CHECKSUM_SIZE;

    if (cmd->recv_data_len != 0) {
        memcpy(cmd->recv_data, msg->data, cmd->recv_data_len);
    } else {
        //do nothing
    }

    return PROT_SUCCESS;

}


static int32_t ofp_usb_send_cmd_packet(uapi_usb_handle *handle, cmd_struct cmd)
{
    msg_struct msg = {0};
    int32_t ret = PROT_ERROR_TRANSFER;
    uint32_t pkg_len = 0;

    memset(&msg, 0, sizeof(msg));
    pkg_len = ofp_fill_usb_cmd_packet(&msg, cmd.cmd, cmd.subcmd, cmd.send_data, cmd.send_data_len);

    ret = uapi_usb_send_msg(handle, ((uint8_t *)(&msg)), pkg_len);
    if (ret < 0) {
        OFP_LOGE("ofp_usb_send_cmd_packet--->uapi_usb_send_msg error \n");
        return PROT_ERROR_TRANSFER;
    }

    return PROT_SUCCESS;
}

static int32_t ofp_usb_recv_cmd_resp_packet(uapi_usb_handle *handle, cmd_struct *cmd, uint32_t len)
{
    msg_struct msg = {0};
    int32_t ret = PROT_ERROR_PARSE;

    memset(&msg, 0, sizeof(msg));
    ret = uapi_usb_recv_msg(handle, ((uint8_t *)(&msg)), len);
    if (ret < 0) {
        OFP_LOGE("ofp_usb_recv_resp_packet--->uapi_usb_recv_msg error ret:%d \n", ret);
        return PROT_ERROR_TRANSFER;
    }


    ret = ofp_check_usb_cmd_resp_packet(&msg, cmd);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_recv_resp_packet--->ofp_parse_usb_cmd_packet error ret:%d \n", ret);
        return PROT_ERROR_PARSE;
    }

    return PROT_SUCCESS;
}


static int32_t ofp_usb_cmd_send_then_recv(uapi_usb_handle *handle, cmd_struct *cmd, ofp_recv_data_param *param)
{
    int32_t ret = PROT_ERROR_PARSE;
    int32_t i = 0;
    ret = ofp_usb_send_cmd_packet(handle, *cmd);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_recv_resp_packet--->ofp_parse_usb_cmd_packet error ret:%d \n", ret);
        return PROT_ERROR_TRANSFER;
    }

    if (param->wait_ms > 0) {
        usleep(param->wait_ms * 1000);
    }

    for (i = 0; i < param->cycle_times; i++) {
        ret = ofp_usb_recv_cmd_resp_packet(handle, cmd, param->recv_len);

        if (ret == PROT_SUCCESS) {
            break;
        } else {
            OFP_LOGE("ofp_usb_cmd_send_then_recv --->%d call ofp_usb_recv_cmd_resp_packet  error ret:%d \n", i, ret);
        }
        usleep(param->cycle_ms * 1000);
    }

    return ret;
}


static int32_t ofp_usb_parse_test_data(cmd_struct *cmd, void *parse)
{
    int32_t ret = PROT_ERROR_OTHER;
    ofp_firmware_version *fw_ver = NULL;
    int32_t i = 0;
    if (cmd->recv_data[i++] != 0u) {
        return PROT_ERROR_OTHER;
    }
    switch (cmd->subcmd){
        case PROT_SUBCMD_READ_FW:
            fw_ver = ((ofp_firmware_version *)parse);
            fw_ver->len = cmd->recv_data_len - i;
            memcpy(fw_ver->firmware_version, cmd->recv_data + i, fw_ver->len);
            ret = PROT_SUCCESS;
            break;
        default:
            break;
    }
    return ret;
}


static int32_t ofp_usb_parse_index_table(cmd_struct *cmd, void *parse)
{
    ofp_index_table *table = NULL;
    int32_t i = 0;
    if (cmd->recv_data[i++] != 0u) {
        return PROT_ERROR_OTHER;
    }
    table = (ofp_index_table *)parse;
    memcpy(table->fp_index, cmd->recv_data + i, OFP_INDEX_TABLE_MAX);

    return PROT_SUCCESS;
}

static int32_t ofp_usb_parse_auto_enroll(cmd_struct *cmd, void *parse)
{
    ofp_enroll_result *result =NULL;
    int32_t ret = PROT_SUCCESS;

    uint8_t confirm_code = cmd->recv_data[0];
    uint8_t param1 = cmd->recv_data[1];
    uint8_t param2 = cmd->recv_data[2];

    result = (ofp_enroll_result *)parse;

    switch (param1) {
        case OFP_ENROLL_VALIDITY_CHECK:
            result->validity_check_result = confirm_code;
            result->validity_check_flag = 1;
            OFP_LOGD("OFP_ENROLL_VALIDITY_CHECK flag:%d  result:%d \n", result->validity_check_flag, confirm_code);
            break;
        case OFP_ENROLL_CAPTURE:
            result->current_enroll_times = param2;
            result->capture_result[param2] = confirm_code;
            OFP_LOGD("OFP_ENROLL_CAPTURE times:%d  result:%d \n", param2, confirm_code);
            break;
        case OFP_ENROLL_CREATE_FEATURE:
            result->current_enroll_times = param2;
            result->create_feature_result[param2] = confirm_code;
            OFP_LOGD("OFP_ENROLL_CREATE_FEATURE times:%d  result:%d \n", param2, confirm_code);
            break;
        case OFP_ENROLL:
            result->enroll_result[param2] = confirm_code;
            result->current_enroll_times = param2;
            result->current_enroll_flag = 1;
            OFP_LOGD("OFP_ENROLL times:%d  result:%d \n", param2, confirm_code);
            break;
        case OFP_ENROLL_MERGE_TEMPLATE:
            result->merge_template_result = confirm_code;
            OFP_LOGD("OFP_ENROLL_MERGE_TEMPLATE result:%d \n", confirm_code);
            break;
        case OFP_ENROLL_CONFLICT:
            result->enroll_conflict_result = confirm_code;
            OFP_LOGD("OFP_ENROLL_CONFLICT result:%d \n", confirm_code);

            break;
        case OFP_ENROLL_STORE_TEMPLATE:
            result->store_template_result = confirm_code;
            result->enroll_finish_flag = 1;
            OFP_LOGD("OFP_ENROLL_STORE_TEMPLATE result:%d \n", confirm_code);
            break;

        default:
            ret = PROT_ERROR_OTHER;
            OFP_LOGE("ofp_usb_parse_auto_enroll enter default case \n");
            break;
    }
    return ret;
}

static int32_t ofp_usb_parse_auto_identify(cmd_struct *cmd, void *parse)
{
    ofp_identify_result *result =NULL;
    int32_t ret = PROT_SUCCESS;
    int i = 0;

    uint8_t confirm_code = cmd->recv_data[0];
    uint8_t param1 = cmd->recv_data[1];

    result = (ofp_identify_result *)parse;

    switch (param1) {
        case OFP_IDENTIFY_VALIDITY_CHECK:
            result->validity_check_result = confirm_code;
            result->validity_check_flag = 1;
            OFP_LOGD("OFP_IDENTIFY_VALIDITY_CHECK flag:%d result:%d \n", result->validity_check_flag, confirm_code);
            break;
        case OFP_IDENTIFY_CAPTURE:
            result->capture_result = confirm_code;
            result->capture_flag = 1;
            OFP_LOGD("OFP_IDENTIFY_CAPTURE flag:%d  result:%d \n", result->capture_flag, confirm_code);
            break;
        case OFP_IDENTIFY_SEARCH:
            result->search_id[0] = (cmd->recv_data[2] << 8) & (0xff00) | (cmd->recv_data[3] << 8);
            result->score = ((cmd->recv_data[4] << 8) & 0xff00) | (cmd->recv_data[5] << 8);
            result->search_num = 1;
            result->search_result = confirm_code;
            result->identify_finish_flag = 1;
            OFP_LOGD("OFP_IDENTIFY_SEARCH id: %d, score: %d, result:%d \n",
                result->search_id[0], result->score, confirm_code);
            break;
        case OFP_IDENTIFY_MUTY_SEARCH:
            result->search_result = confirm_code;
            result->search_num = cmd->recv_data[2];

            result->identify_finish_flag = 1;
            OFP_LOGD("OFP_IDENTIFY_MUTY_SEARCH result:%d num:%d \n", confirm_code,result->search_num);
            for (i = 0; i < result->search_num; i++) {
                result->search_id[i] = cmd->recv_data[3 + i];
                OFP_LOGD("%d ", result->search_id[i]);
            }
            OFP_LOGD("\n");
            break;
        default:
            ret = PROT_ERROR_OTHER;
            OFP_LOGE("ofp_usb_parse_auto_enroll enter default case \n");
            break;
    }
    return ret;
}

static int32_t ofp_usb_parse_cmd_data(cmd_struct *cmd, void *parse)
{
    int32_t ret = PROT_SUCCESS;
    switch (cmd->cmd){
        case PROT_CMD_TEST_TYPE:
            ret = ofp_usb_parse_test_data(cmd, parse);
            break;
        case PROT_CMD_READINDEXTABLE:
            ret = ofp_usb_parse_index_table(cmd, parse);
            break;
        case PROT_CMD_AUTOENROLL:
            ret = ofp_usb_parse_auto_enroll(cmd, parse);
            break;
        case PROT_CMD_AUTOIDENTIFY:
            ret = ofp_usb_parse_auto_identify(cmd, parse);
            break;
        case PROT_CMD_EMPTY:
        case PROT_CMD_DELCHAR:
        case PROT_CMD_CANCEL:
            if (cmd->recv_data[0] == 0x00) {
                ret = PROT_SUCCESS;
            } else {
                ret = PROT_ERROR_OTHER;
            }
            break;
        default:
            OFP_LOGE("ofp_usb_parse_cmd_data enter default case \n");
            ret = PROT_ERROR_OTHER;
            break;
    }

    return ret;
}

int32_t ofp_usb_get_firmware_version(uapi_usb_handle *handle, ofp_firmware_version *fw_ver)
{
    cmd_struct cmd = {0};

    int32_t ret;
    ofp_recv_data_param param = {0};

    OFP_LOGD("ofp_app_get_firmware_version ==================> enter\n");

    if ((handle == NULL) || (fw_ver == NULL) || (handle->handle == NULL)) {
        OFP_LOGE("ofp_app_get_firmware_version param error \n");
        return -1;
    }
    memset(&cmd, 0, sizeof(cmd));

    cmd.cmd = PROT_CMD_TEST_TYPE;
    cmd.subcmd = PROT_SUBCMD_READ_FW;
    cmd.send_data_len = 0;

    ofp_recv_param_init(&param, 64, 20, 10, 20);
    ret = ofp_usb_cmd_send_then_recv(handle, &cmd, &param);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_app_get_firmware_version--->ofp_usb_cmd_send_then_recv error \n");
        return PROT_ERROR_OTHER;
    }

    ret = ofp_usb_parse_cmd_data(&cmd, fw_ver);
    if (ret != PROT_RESP_OK) {
        OFP_LOGE("ofp_app_get_firmware_version--->ofp_parse_usb_cmd_packet error \n");
        return PROT_ERROR_OTHER;
    }

    OFP_LOGD("ofp_app_get_firmware_version <================== exit\n");

    return PROT_SUCCESS;

}

int32_t ofp_usb_goto_boot(uapi_usb_handle *handle)
{
    msg_struct msg = {0};
    int32_t ret;
    cmd_struct cmd = {0};
    uint8_t rtboot_cmd_data[OFP_LEN_8] = {0x5a, 0xa5, 0x55, 0xaa, 0x42, 0x44, 0x43, 0x47};

    OFP_LOGD("ofp_app_goto_boot ==================> enter\n");
    if ((handle == NULL) || (handle->handle == NULL)) {
        OFP_LOGE("ofp_app_get_firmware_version param error \n");
        return -1;
    }

    memset(&cmd, 0, sizeof(cmd));

    cmd.cmd = PROT_CMD_RTBOOT;
    cmd.subcmd = PROT_SUBCMD_NULL;
    memcpy(cmd.send_data, rtboot_cmd_data, OFP_LEN_8);
    cmd.send_data_len = 8;

    ret = ofp_usb_send_cmd_packet(handle, cmd);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_recv_resp_packet--->ofp_parse_usb_cmd_packet error ret:%d \n", ret);
        return PROT_ERROR_TRANSFER;
    }

    memset(&msg, 0, sizeof(msg));
    ret = uapi_usb_recv_msg(handle, ((uint8_t *)(&msg)), sizeof(msg));
    if (ret < 0) {
        OFP_LOGE("ofp_app_goto_boot--->uapi_usb_recv_msg error ret:%d \n", ret);
        return -1;
    }
    OFP_LOGD("ofp_app_goto_boot <================== exit\n");
    return PROT_SUCCESS;
}


int32_t ofp_usb_read_index_table(uapi_usb_handle *handle, uint8_t page_number, ofp_index_table *table)
{
    cmd_struct cmd = {0};

    int32_t ret;
    ofp_recv_data_param param = {0};

    OFP_LOGD("ofp_usb_read_index_table ==================> enter\n");

    if ((handle == NULL) || (handle->handle == NULL)) {
        OFP_LOGE("ofp_usb_read_index_table param error \n");
        return -1;
    }
    memset(&cmd, 0, sizeof(cmd));

    cmd.cmd = PROT_CMD_READINDEXTABLE;
    cmd.subcmd = PROT_SUBCMD_NULL;
    cmd.send_data[0] = page_number;
    cmd.send_data_len = 1;
    ofp_recv_param_init(&param, 64, 20, 10, 20);

    ret = ofp_usb_cmd_send_then_recv(handle, &cmd, &param);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_read_index_table--->ofp_usb_cmd_send_then_recv error \n");
        return PROT_ERROR_OTHER;
    }

    ret = ofp_usb_parse_cmd_data(&cmd, table);
    if (ret != PROT_RESP_OK) {
        OFP_LOGE("ofp_usb_read_index_table--->ofp_parse_usb_cmd_packet error \n");
        return PROT_ERROR_OTHER;
    }

    OFP_LOGD("ofp_usb_read_index_table <================== exit\n");

    return PROT_SUCCESS;
}

int32_t ofp_usb_auto_enroll(uapi_usb_handle *handle, ofp_enroll_input_setting in_set, ofp_enroll_result *result)
{
    cmd_struct cmd = {0};

    int32_t ret;
    ofp_recv_data_param param = {0};

    OFP_LOGD("ofp_usb_auto_enroll ==================> enter\n");

    if ((handle == NULL) || (handle->handle == NULL)) {
        OFP_LOGE("ofp_usb_auto_enroll param error \n");
        return -1;
    }
    memset(&cmd, 0, sizeof(cmd));

    cmd.cmd = PROT_CMD_AUTOENROLL;
    cmd.subcmd = PROT_SUBCMD_NULL;
    cmd.send_data[0] = (in_set.id >> 8) & 0xff;
    cmd.send_data[1] = in_set.id & 0xff;
    cmd.send_data[2] = in_set.times;
    cmd.send_data[3] = (in_set.param >> 8) & 0xff;
    cmd.send_data[4] = in_set.param & 0xff;
    cmd.send_data_len = 5;
    ofp_recv_param_init(&param, 64, 20, 3, 20);

    ret = ofp_usb_cmd_send_then_recv(handle, &cmd, &param);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_auto_enroll--->ofp_usb_cmd_send_then_recv error \n");
        return PROT_ERROR_OTHER;
    }

    ret = ofp_usb_parse_cmd_data(&cmd, result);
    if (ret != PROT_RESP_OK) {
        OFP_LOGE("ofp_usb_auto_enroll--->ofp_parse_usb_cmd_packet error \n");
        return PROT_ERROR_OTHER;
    }

    OFP_LOGD("ofp_usb_auto_enroll <================== exit\n");

    return PROT_SUCCESS;
}

int32_t ofp_usb_get_enroll_result(uapi_usb_handle *handle, ofp_enroll_result *result)
{
    int32_t ret = PROT_SUCCESS;
    cmd_struct cmd = {0};

    OFP_LOGD("ofp_usb_get_enroll_result ==================> enter\n");
    if ((handle == NULL) || (handle->handle == NULL)) {
        OFP_LOGE("ofp_usb_get_enroll_result param error \n");
        return -1;
    }

    memset(&cmd, 0, sizeof(cmd));
    cmd.cmd = PROT_CMD_AUTOENROLL;
    ret = ofp_usb_recv_cmd_resp_packet(handle, &cmd, 64);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_get_enroll_result--->ofp_parse_usb_cmd_packet error ret:%d \n", ret);
        return PROT_ERROR_PARSE;
    }
    ret = ofp_usb_parse_cmd_data(&cmd, result);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_parse_cmd_data--->ofp_parse_usb_cmd_packet error ret:%d \n", ret);
        return PROT_ERROR_PARSE;
    }

    OFP_LOGD("ofp_usb_get_enroll_result <================== exit\n");
    return ret;

}

int32_t ofp_usb_auto_identify(uapi_usb_handle *handle, ofp_identify_input_setting in_set, ofp_identify_result *result)
{
    cmd_struct cmd = {0};

    int32_t ret;
    ofp_recv_data_param param = {0};

    OFP_LOGD("ofp_usb_auto_identify ==================> enter\n");

    if ((handle == NULL) || (handle->handle == NULL)) {
        OFP_LOGE("ofp_usb_auto_enroll param error \n");
        return -1;
    }
    memset(&cmd, 0, sizeof(cmd));

    cmd.cmd = PROT_CMD_AUTOIDENTIFY;
    cmd.subcmd = PROT_SUBCMD_NULL;
    cmd.send_data[0] = in_set.secure_level;
    cmd.send_data[1] = (in_set.fp_id >> 8) & 0xff;
    cmd.send_data[2] = in_set.fp_id & 0xff;
    cmd.send_data[3] = (in_set.system_id >> 8) & 0xff;
    cmd.send_data[4] = in_set.system_id & 0xff;
    cmd.send_data_len = 5;

    ofp_recv_param_init(&param, 64, 20, 3, 20);

    ret = ofp_usb_cmd_send_then_recv(handle, &cmd, &param);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_auto_identify--->ofp_usb_cmd_send_then_recv error \n");
        return PROT_ERROR_OTHER;
    }

    ret = ofp_usb_parse_cmd_data(&cmd, result);
    if (ret != PROT_RESP_OK) {
        OFP_LOGE("ofp_usb_auto_identify--->ofp_parse_usb_cmd_packet error \n");
        return PROT_ERROR_OTHER;
    }

    OFP_LOGD("ofp_usb_auto_identify <================== exit\n");

    return PROT_SUCCESS;
}

int32_t ofp_usb_get_identify_result(uapi_usb_handle *handle, ofp_identify_result *result)
{
    int32_t ret = PROT_SUCCESS;
    cmd_struct cmd = {0};

    OFP_LOGD("ofp_usb_get_identify_result ==================> enter\n");
    if ((handle == NULL) || (handle->handle == NULL)) {
        OFP_LOGE("ofp_usb_get_identify_result param error \n");
        return -1;
    }

    memset(&cmd, 0, sizeof(cmd));
    cmd.cmd = PROT_CMD_AUTOIDENTIFY;
    ret = ofp_usb_recv_cmd_resp_packet(handle, &cmd, 64);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_get_identify_result--->ofp_parse_usb_cmd_packet error ret:%d \n", ret);
        return PROT_ERROR_PARSE;
    }
    ret = ofp_usb_parse_cmd_data(&cmd, result);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_parse_cmd_data--->ofp_parse_usb_cmd_packet error ret:%d \n", ret);
        return PROT_ERROR_PARSE;
    }

    OFP_LOGD("ofp_usb_get_identify_result <================== exit\n");
    return ret;

}



int32_t ofp_usb_cancel(uapi_usb_handle *handle)
{
    cmd_struct cmd = {0};

    int32_t ret = PROT_SUCCESS;
    ofp_recv_data_param param = {0};

    OFP_LOGD("ofp_usb_fp_cancel ==================> enter\n");

    if ((handle == NULL) || (handle->handle == NULL)) {
        OFP_LOGE("ofp_usb_fp_cancel param error \n");
        return -1;
    }
    memset(&cmd, 0, sizeof(cmd));

    cmd.cmd = PROT_CMD_CANCEL;
    cmd.subcmd = PROT_SUBCMD_NULL;
    cmd.send_data_len = 0;
    ofp_recv_param_init(&param, 64, 20, 5, 20);

    ret = ofp_usb_cmd_send_then_recv(handle, &cmd, &param);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_fp_cancel--->ofp_usb_cmd_send_then_recv error \n");
        return PROT_ERROR_OTHER;
    }

    ret = ofp_usb_parse_cmd_data(&cmd, (void *)NULL);
    if (ret != PROT_RESP_OK) {
        OFP_LOGE("ofp_usb_fp_cancel--->ofp_parse_usb_cmd_packet error \n");
        return PROT_ERROR_OTHER;
    }

    OFP_LOGD("ofp_usb_fp_cancel <================== exit\n");
    return ret;

}

int32_t ofp_usb_delete_template(uapi_usb_handle *handle, uint16_t enroll_id, uint16_t num)
{
    cmd_struct cmd = {0};

    int32_t ret = PROT_SUCCESS;
    ofp_recv_data_param param = {0};

    OFP_LOGD("ofp_usb_delete_template ==================> enter\n");

    if ((handle == NULL) || (handle->handle == NULL)) {
        OFP_LOGE("ofp_usb_delete_template param error \n");
        return -1;
    }
    memset(&cmd, 0, sizeof(cmd));

    cmd.cmd = PROT_CMD_DELCHAR;
    cmd.subcmd = PROT_SUBCMD_NULL;
    cmd.send_data[0] = (enroll_id >> 8) & 0xff;
    cmd.send_data[1] = enroll_id & 0xff;
    cmd.send_data[2] = (num >> 8) & 0xff;
    cmd.send_data[3] = num & 0xff;
    cmd.send_data_len = 4;
    ofp_recv_param_init(&param, 64, 20, 5, 20);

    ret = ofp_usb_cmd_send_then_recv(handle, &cmd, &param);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_delete_template--->ofp_usb_cmd_send_then_recv error \n");
        return PROT_ERROR_OTHER;
    }

    ret = ofp_usb_parse_cmd_data(&cmd, (void *)NULL);
    if (ret != PROT_RESP_OK) {
        OFP_LOGE("ofp_usb_delete_template--->ofp_parse_usb_cmd_packet error \n");
        return PROT_ERROR_OTHER;
    }

    OFP_LOGD("ofp_usb_delete_template <================== exit\n");
    return ret;
}

int32_t ofp_usb_empty(uapi_usb_handle *handle)
{
    cmd_struct cmd = {0};

    int32_t ret = PROT_SUCCESS;
    ofp_recv_data_param param = {0};

    OFP_LOGD("ofp_usb_delete_template ==================> enter\n");

    if ((handle == NULL) || (handle->handle == NULL)) {
        OFP_LOGE("ofp_usb_delete_template param error \n");
        return -1;
    }
    memset(&cmd, 0, sizeof(cmd));

    cmd.cmd = PROT_CMD_EMPTY;
    cmd.subcmd = PROT_SUBCMD_NULL;
    cmd.send_data_len = 0;

    ofp_recv_param_init(&param, 64, 20, 5, 20);

    ret = ofp_usb_cmd_send_then_recv(handle, &cmd, &param);
    if (ret != PROT_SUCCESS) {
        OFP_LOGE("ofp_usb_delete_template--->ofp_usb_cmd_send_then_recv error \n");
        return PROT_ERROR_OTHER;
    }

    ret = ofp_usb_parse_cmd_data(&cmd, (void *)NULL);
    if (ret != PROT_RESP_OK) {
        OFP_LOGE("ofp_usb_delete_template--->ofp_parse_usb_cmd_packet error \n");
        return PROT_ERROR_OTHER;
    }

    OFP_LOGD("ofp_usb_delete_template <================== exit\n");
    return ret;
}




